﻿Imports System
Imports System.CodeDom
Imports System.Collections
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.ComponentModel.Design.Serialization
Imports System.Reflection
Imports System.Workflow.ComponentModel

Namespace System.Workflow.ComponentModel.Serialization
    Public Class DependencyObjectCodeDomSerializer
        Inherits CodeDomSerializer
        ' Methods
        Public Overrides Function Serialize(ByVal manager As IDesignerSerializationManager, ByVal obj As Object) As Object
            If (manager Is Nothing) Then
                Throw New ArgumentNullException("manager")
            End If
            If (manager.Context Is Nothing) Then
                Throw New ArgumentException("manager", SR.GetString("Error_MissingContextProperty"))
            End If
            If (obj Is Nothing) Then
                Throw New ArgumentNullException("obj")
            End If
            Dim component As DependencyObject = [TryCast](obj,DependencyObject)
            If (component Is Nothing) Then
                Throw New ArgumentException(SR.GetString("Error_UnexpectedArgumentType", New Object() { GetType(DependencyObject).FullName }), "obj")
            End If
            Dim context As Activity = [TryCast](obj,Activity)
            If (Not context Is Nothing) Then
                manager.Context.Push(context)
            End If
            Dim statements As CodeStatementCollection = Nothing
            Try 
                If (Not context Is Nothing) Then
                    Dim serializer As CodeDomSerializer = [TryCast](manager.GetSerializer(GetType(Component), GetType(CodeDomSerializer)),CodeDomSerializer)
                    If (serializer Is Nothing) Then
                        Throw New InvalidOperationException(SR.GetString("General_MissingService", New Object() { GetType(CodeDomSerializer).FullName }))
                    End If
                    statements = [TryCast](serializer.Serialize(manager, context),CodeStatementCollection)
                Else
                    statements = [TryCast](MyBase.Serialize(manager, obj),CodeStatementCollection)
                End If
                If (statements Is Nothing) Then
                    Return statements
                End If
                Dim statements2 As New CodeStatementCollection(statements)
                Dim targetObject As CodeExpression = MyBase.SerializeToExpression(manager, obj)
                If (targetObject Is Nothing) Then
                    Return statements
                End If
                Dim list As New ArrayList
                Dim list2 As New List([Of] DependencyProperty)(component.MetaDependencyProperties)
                Dim property As DependencyProperty
                For Each property In component.DependencyPropertyValues.Keys
                    If (Not [property].IsAttached OrElse ((Not [property].IsEvent OrElse ([property].OwnerType.GetField(([property].Name & "Event"), (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.DeclaredOnly))) Is Nothing)) AndAlso ([property].IsEvent OrElse ([property].OwnerType.GetField(([property].Name & "Property"), (BindingFlags.Public Or (BindingFlags.Static Or BindingFlags.DeclaredOnly))) Is Nothing)))) Then
                        [Continue] For
                    End If
                    list2.Add([property])
                Next
                Dim property2 As DependencyProperty
                For Each property2 In list2
                    Dim binding As Object = Nothing
                    If component.IsBindingSet(property2) Then
                        binding = component.GetBinding(property2)
                    ElseIf Not property2.IsEvent Then
                        binding = component.GetValue(property2)
                    Else
                        binding = component.GetHandler(property2)
                    End If
                    If ((Not binding Is Nothing) AndAlso (property2.IsAttached OrElse (Not property2.DefaultMetadata.IsMetaProperty AndAlso TypeOf binding Is ActivityBind))) Then
                        Dim attributes As Object() = property2.DefaultMetadata.GetAttributes(GetType(DesignerSerializationVisibilityAttribute))
                        If (attributes.Length > 0) Then
                            Dim attribute As DesignerSerializationVisibilityAttribute = [TryCast](attributes(0),DesignerSerializationVisibilityAttribute)
                            If (attribute.Visibility = DesignerSerializationVisibility.Hidden) Then
                                [Continue] For
                            End If
                        End If
                        Dim expression2 As CodeExpression = Nothing
                        Dim name As String = (property2.Name & If(property2.IsEvent, "Event", "Property"))
                        Dim field As FieldInfo = property2.OwnerType.GetField(name, (BindingFlags.NonPublic Or (BindingFlags.Public Or BindingFlags.Static)))
                        If ((Not field Is Nothing) AndAlso Not field.IsPublic) Then
                            expression2 = New CodeMethodInvokeExpression(New CodeTypeReferenceExpression(GetType(DependencyProperty)), "FromName", New CodeExpression() { New CodePrimitiveExpression(property2.Name), New CodeTypeOfExpression(property2.OwnerType) })
                        Else
                            expression2 = New CodeFieldReferenceExpression(New CodeTypeReferenceExpression(property2.OwnerType), name)
                        End If
                        Dim expression As CodeExpression = MyBase.SerializeToExpression(manager, binding)
                        If ((Not expression2 Is Nothing) AndAlso (Not expression Is Nothing)) Then
                            Dim expression4 As CodeMethodInvokeExpression = Nothing
                            If TypeOf binding Is ActivityBind Then
                                expression4 = New CodeMethodInvokeExpression(targetObject, "SetBinding", New CodeExpression() { expression2, New CodeCastExpression(New CodeTypeReference(GetType(ActivityBind)), expression) })
                            Else
                                expression4 = New CodeMethodInvokeExpression(targetObject, If(property2.IsEvent, "AddHandler", "SetValue"), New CodeExpression() { expression2, expression })
                            End If
                            statements.Add(expression4)
                            Dim statement As CodeStatement
                            For Each statement In statements2
                                If (TypeOf statement Is CodeAssignStatement AndAlso TypeOf DirectCast(statement, CodeAssignStatement).Left Is CodePropertyReferenceExpression) Then
                                    Dim left As CodePropertyReferenceExpression = [TryCast](DirectCast(statement, CodeAssignStatement).Left,CodePropertyReferenceExpression)
                                    If ((left.PropertyName = property2.Name) AndAlso left.TargetObject.Equals(targetObject)) Then
                                        statements.Remove(statement)
                                    End If
                                End If
                            Next
                        End If
                        list.Add(property2)
                    End If
                Next
                If Not TypeOf manager.GetService(GetType(IEventBindingService)) Is IEventBindingService Then
                    Dim descriptor As EventDescriptor
                    For Each descriptor In TypeDescriptor.GetEvents(component)
                        Dim eventHandlerName As String = WorkflowMarkupSerializationHelpers.GetEventHandlerName(component, descriptor.Name)
                        If Not String.IsNullOrEmpty(eventHandlerName) Then
                            Dim eventRef As New CodeEventReferenceExpression(targetObject, descriptor.Name)
                            Dim listener As New CodeDelegateCreateExpression(New CodeTypeReference(descriptor.EventType), New CodeThisReferenceExpression, eventHandlerName)
                            statements.Add(New CodeAttachEventStatement(eventRef, listener))
                        End If
                    Next
                End If
                If Not component.UserData.Contains(UserDataKeys.DesignTimeTypeNames) Then
                    Return statements
                End If
                Dim hashtable As Hashtable = [TryCast](component.UserData.Item(UserDataKeys.DesignTimeTypeNames),Hashtable)
                Dim obj4 As Object
                For Each obj4 In hashtable.Keys
                    Dim str3 As String = Nothing
                    Dim fullName As String = Nothing
                    Dim str5 As String = [TryCast](hashtable.Item(obj4),String)
                    Dim item As DependencyProperty = [TryCast](obj4,DependencyProperty)
                    If (Not item Is Nothing) Then
                        If list.Contains(item) Then
                            [Continue] For
                        End If
                        Dim objArray2 As Object() = item.DefaultMetadata.GetAttributes(GetType(DesignerSerializationVisibilityAttribute))
                        If (objArray2.Length > 0) Then
                            Dim attribute2 As DesignerSerializationVisibilityAttribute = [TryCast](objArray2(0),DesignerSerializationVisibilityAttribute)
                            If (attribute2.Visibility = DesignerSerializationVisibility.Hidden) Then
                                [Continue] For
                            End If
                        End If
                        str3 = item.Name
                        fullName = item.OwnerType.FullName
                    ElseIf TypeOf obj4 Is String Then
                        Dim length As Integer = CStr(obj4).LastIndexOf("."c)
                        If (length <> -1) Then
                            fullName = CStr(obj4).Substring(0, length)
                            str3 = CStr(obj4).Substring((length + 1))
                        End If
                    End If
                    If ((Not String.IsNullOrEmpty(str5) AndAlso Not String.IsNullOrEmpty(str3)) AndAlso Not String.IsNullOrEmpty(fullName)) Then
                        If (fullName = obj.GetType.FullName) Then
                            Dim expression8 As New CodePropertyReferenceExpression(targetObject, str3)
                            statements.Add(New CodeAssignStatement(expression8, New CodeTypeOfExpression(str5)))
                            [Continue] For
                        End If
                        Dim expression9 As CodeExpression = New CodeFieldReferenceExpression(New CodeTypeReferenceExpression(fullName), (str3 & "Property"))
                        Dim expression10 As CodeExpression = New CodeTypeOfExpression(str5)
                        statements.Add(New CodeMethodInvokeExpression(targetObject, "SetValue", New CodeExpression() { expression9, expression10 }))
                    End If
                Next
            Finally
                If (Not context Is Nothing) Then
                    manager.Context.Pop
                End If
            End Try
            Return statements
        End Function

    End Class
End Namespace

